try:
    from xml.etree import ElementTree # for Python 2.5 users
except ImportError:
    from elementtree import ElementTree
import gdata.calendar.service
import gdata.service
import atom.service
import gdata.calendar
import atom
import datetime

from gdata.service import BadAuthentication, RequestError
from socket import gaierror


class GCalHandler(object):

    def __init__(self, login, passwd):
        self.calendar_service = gdata.calendar.service.CalendarService()
        self.calendar_service.email = login
        self.calendar_service.password = passwd
        self.calendar_service.ProgrammaticLogin()

    def getOwnCalendars(self):
        """ this is used to init the list in the gui
        """
        feed = self.calendar_service.GetOwnCalendarsFeed()
        calendar_infos = {
            'ids': [],
            'titles': [],
            }
        for i, a_calendar in enumerate(feed.entry):
            cal_id = a_calendar.id.text.split('/')[-1]
            cal_id = cal_id.replace('%40', '@')
            calendar_infos['ids'].append(cal_id)
            calendar_infos['titles'].append(a_calendar.title.text)
        return calendar_infos

    def InsertSingleEvent(self, calendar_id, start_time, end_time,
                          title='',
                          content=''):
        """ writing into remote calendar
        """
        event = gdata.calendar.CalendarEventEntry()
        event.title = atom.Title(text=title)
        event.content = atom.Content(text=content)

        start_time = start_time.isoformat()
        end_time = end_time.isoformat()
        event.when.append(gdata.calendar.When(start_time=start_time,
                                              end_time=end_time))
        self.calendar_service.InsertEvent(event, '/calendar/feeds/%s/private/full' % calendar_id)

    def makeDelta(self, time_string):
        """ convert a '08:30' time string to a timedelta object
        """
        hours, mins = map(int, time_string.split(':'))
        return datetime.timedelta(hours=hours, minutes=mins)

    def DateRangeQuery(self, calendar_id, start_date, end_date, workday_length):
        """ actually queries the online calendar
        XXX: does report formatting too: this is bad
        XXX: is this sorted ?
        """
        query = gdata.calendar.service.CalendarEventQuery(calendar_id, 'private', 'full')
        query.start_min = start_date
        query.start_max = end_date
        feed = self.calendar_service.CalendarQuery(query)

        total = datetime.timedelta()
        workday_length = self.makeDelta(workday_length) # still in '08:30' format
        report = ''
        for i, an_event in enumerate(feed.entry):
            for a_when in an_event.when:
                try:
                    start = datetime.datetime.strptime(a_when.start_time, '%Y-%m-%dT%H:%M:%S.%f+02:00')
                    end = datetime.datetime.strptime(a_when.end_time, '%Y-%m-%dT%H:%M:%S.%f+02:00')
                    report += ' %s -> %s\n' % (start.strftime('%d-%m-%Y %H:%M'),
                                               end.strftime('%d-%m-%Y %H:%M'))
                    subtotal = end - start
                except ValueError: # full day activity
                    subtotal = workday_length
                    report += ' %s\n' % (a_when.start_time)
                report += '\t%s\t: %s\n' % (subtotal, an_event.title.text,)
                total += subtotal
        report += _('\nin hours: %s') % (total.seconds / 60 / 60.0 + total.days * 24)
        return report

    def DayQuery(self, calendar_id, workday_length):
        """ the google cal api doesn't include the upper bound
        """
        d = datetime.date.today()
        end_date = d + datetime.timedelta(days=1)
        report = self.DateRangeQuery(calendar_id, str(d),
                                     str(end_date), workday_length)
        return report

    def WeekQuery(self, calendar_id, workday_length):
        """ this is monday to friday
        """
        d = datetime.date.today()
        start_date = d + datetime.timedelta(days= -d.weekday())
        end_date = start_date + datetime.timedelta(days=5)
        report = self.DateRangeQuery(calendar_id, str(start_date),
                                     str(end_date), workday_length)
        return report

    def MonthQuery(self, calendar_id, workday_length):
        """ the google api excludes the upper bound
        this is why we keep 1st day of next month
        """
        d = datetime.date.today()
        start_date = datetime.date(d.year, d.month, 1)
        end_date = datetime.date(d.year, d.month + 1, 1)
        report = self.DateRangeQuery(calendar_id, str(start_date),
                                     str(end_date), workday_length)
        return report

    def CustomQuery(self, calendar_id, start_date, end_date, workday_length):
        """ +1  day also here
        """
        end_date.SetDay(end_date.GetDay() + 1)
        report = self.DateRangeQuery(calendar_id, start_date.FormatISODate(),
                                     end_date.FormatISODate(), workday_length)
        return report

